//
// table.h
// the central table type, based on khash
//
// (c) 2008 why the lucky stiff, the freelance professor
//
#ifndef POTION_TABLE_H
#define POTION_TABLE_H

#include "potion.h"
#include "khash.h"

typedef PN (*PN_MCACHE_FUNC)(unsigned int hash);
// TODO: ensure the random PNUniq is truly unique for strings
typedef PN (*PN_IVAR_FUNC)(PNUniq hash);

struct PNVtable {
  PN_OBJECT_HEADER
  PN parent;              // 指向父虚表， lobby 为 nil 。
  PNType type;            // 对应的类型数值
  PN_SIZE ivlen;          // 属性数量
  PN ivars;               // 属性元组 | nil
  // TODO hsq .methods 有必要改为按需创建？
  vPN(Table) methods;     // 方法表
  PN ctor, call, callset; // ctor: 构造函数 ｜ nil ，返回 self ；
  PN_MCACHE_FUNC mcache;  // 查找方法，汇编代码
  PN_IVAR_FUNC ivfunc;    // 查找属性，汇编代码
  PN name;                // PNString
};

struct PNTable {
  PN_OBJECT_HEADER
  PN_TABLE_HEADER
  char table[0];
};

KHASH_MAP_INIT_PN(PN, struct PNTable);
KHASH_MAP_INIT_STR(str, struct PNTable);

// 遍历哈希表：正序； block 中不要出现变量 t 和 k 。
// TODO hsq 如何封装 kh_key(PN, t, k) 和 kh_val(PN, t, k) ？
#define KH_EACH_ASC(name, h, block) { \
    vPN(Table) t = (struct PNTable *)h; \
    for (unsigned k = kh_begin(t); k != kh_end(t); ++k) { \
      if (kh_exist(name, t, k)) block \
    } \
  }
// 遍历哈希表：逆序； block 中不要出现变量 t 和 k 。
#define KH_EACH_DESC(name, h, block) { \
    vPN(Table) t = (struct PNTable *)h; \
    for (unsigned k = kh_end(t); k-- > kh_begin(t); ) { \
      if (kh_exist(name, t, k)) block \
    } \
  }

#endif
